// Windows/Process.h

#ifndef __WINDOWS_PROCESS_H
#define __WINDOWS_PROCESS_H

#include <psapi.h>

#include "Defs.h"
#include "Threading/Thread.h"

namespace Common {

namespace System {

class CProcess: public Threading::CHandle
{
public:
  bool Open(DWORD desiredAccess, bool inheritHandle, DWORD processId)
  {
    m_hHandle = ::OpenProcess(desiredAccess, inheritHandle, processId);
	if(NULL == m_hHandle)
		m_hHandle = INVALID_HANDLE_VALUE;
    return (m_hHandle != 0);
  }

  #ifndef UNDER_CE

  bool GetExitCodeProcess(LPDWORD lpExitCode) { return BOOLToBool(::GetExitCodeProcess(m_hHandle, lpExitCode)); }
  bool Terminate(UINT exitCode) { return BOOLToBool(::TerminateProcess(m_hHandle, exitCode)); }
  #if(WINVER >= 0x0500)
  DWORD GetGuiResources (DWORD uiFlags) { return ::GetGuiResources(m_hHandle, uiFlags); }
  #endif
  bool SetPriorityClass(DWORD dwPriorityClass) { return BOOLToBool(::SetPriorityClass(m_hHandle, dwPriorityClass)); }
  DWORD GetPriorityClass() { return ::GetPriorityClass(m_hHandle); }
  bool GetIoCounters(PIO_COUNTERS lpIoCounters ) { return BOOLToBool(::GetProcessIoCounters(m_hHandle, lpIoCounters )); }

  bool GetTimes(LPFILETIME creationTime, LPFILETIME exitTime, LPFILETIME kernelTime, LPFILETIME userTime)
    { return BOOLToBool(::GetProcessTimes(m_hHandle, creationTime, exitTime, kernelTime, userTime)); }

  DWORD WaitForInputIdle(DWORD milliseconds) { return ::WaitForInputIdle(m_hHandle, milliseconds);  }

  // Debug

  bool ReadMemory(LPCVOID baseAddress, LPVOID buffer, SIZE_T size, SIZE_T* numberOfBytesRead)
    { return BOOLToBool(::ReadProcessMemory(m_hHandle, baseAddress, buffer, size, numberOfBytesRead));  }

  bool WriteMemory(LPVOID baseAddress, LPCVOID buffer, SIZE_T size, SIZE_T* numberOfBytesWritten)
    { return BOOLToBool(::WriteProcessMemory(m_hHandle, baseAddress, buffer, size, numberOfBytesWritten)); }

  bool FlushInstructionCache(LPCVOID baseAddress = 0, SIZE_T size = 0)
    { return BOOLToBool(::FlushInstructionCache(m_hHandle, baseAddress, size)); }

  LPVOID VirtualAlloc(LPVOID address, SIZE_T size, DWORD allocationType, DWORD protect)
    { return VirtualAllocEx(m_hHandle, address, size, allocationType, protect);  }

  bool VirtualFree(LPVOID address, SIZE_T size, DWORD freeType)
    { return BOOLToBool(::VirtualFreeEx(m_hHandle, address, size, freeType)); }

  // Process Status API (PSAPI)

  bool EmptyWorkingSet()
    { return BOOLToBool(::EmptyWorkingSet(m_hHandle)); }
  bool EnumModules(HMODULE *hModules, DWORD arraySizeInBytes, LPDWORD receivedBytes)
    { return BOOLToBool(::EnumProcessModules(m_hHandle, hModules, arraySizeInBytes, receivedBytes)); }

  DWORD MyGetModuleBaseName(HMODULE hModule, LPTSTR baseName, DWORD size)
    { return ::GetModuleBaseName(m_hHandle, hModule, baseName, size); }
  bool MyGetModuleBaseName(HMODULE hModule, CString &name)
  {
    const int length = 1000;
    DWORD resultLen = MyGetModuleBaseName(hModule, name.GetBuffer(length), length);
    name.ReleaseBuffer();
    return (resultLen != 0);
  }

  DWORD MyGetModuleFileNameEx(HMODULE hModule, LPTSTR baseName, DWORD size)
    { return ::GetModuleFileNameEx(m_hHandle, hModule, baseName, size); }
  bool MyGetModuleFileNameEx(HMODULE hModule, CString &name)
  {
    const int length = MAX_PATH + 100;
    DWORD resultLen = MyGetModuleFileNameEx(hModule, name.GetBuffer(length), length);
    name.ReleaseBuffer();
    return (resultLen != 0);
  }

  bool GetModuleInformation(HMODULE hModule, LPMODULEINFO moduleInfo)
    { return BOOLToBool(::GetModuleInformation(m_hHandle, hModule, moduleInfo, sizeof(MODULEINFO))); }
  bool GetMemoryInfo(PPROCESS_MEMORY_COUNTERS memCounters)
    { return BOOLToBool(::GetProcessMemoryInfo(m_hHandle, memCounters, sizeof(PROCESS_MEMORY_COUNTERS))); }

  #endif

  DWORD Create(LPCWSTR imageName, const CString &params, LPCWSTR curDir);

};

DWORD MyCreateProcess(LPCWSTR imageName, const CString &params);

}
}
#endif
